package document

import (
	"context"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/cloudwego/eino-ext/components/document/parser/html"
	"github.com/cloudwego/eino-ext/components/document/parser/pdf"
	"github.com/cloudwego/eino/components/document/parser"
	"github.com/cloudwego/eino/schema"
	"github.com/pelletier/go-toml/v2"
)

// 导入errors.go中定义的错误变量

// DocumentParser 定义文档解析接口
type DocumentParser interface {
	Parse(ctx context.Context, reader io.Reader, options ...parser.Option) ([]*schema.Document, error)
}

// HTMLParserConfig HTML解析器配置结构
type HTMLParserConfig struct {
	RemoveScripts bool   `toml:"remove_scripts"`
	RemoveStyles  bool   `toml:"remove_styles"`
	IncludeImages bool   `toml:"include_images"`
	BaseURL       string `toml:"base_url"`
	MaxDepth      int    `toml:"max_depth"`
}

// ParseHTML 解析HTML文档
// 参数:
//   - ctx: 上下文
//   - htmlContent: HTML内容字节数组
//   - uri: 可选的文档URI
//   - extraMeta: 可选的额外元数据
//
// 返回:
//   - []*schema.Document: 解析后的文档列表
//   - error: 错误信息
func ParseHTML(ctx context.Context, htmlContent []byte, uri string, extraMeta map[string]any) ([]*schema.Document, error) {
	// 参数验证
	if htmlContent == nil {
		return nil, fmt.Errorf("%w: HTML内容不能为空", ErrInvalidParameter)
	}

	// 加载HTML解析器配置
	config, err := loadHTMLParserConfig()
	if err != nil {
		// 如果加载配置失败，使用默认配置并记录警告
		fmt.Printf("警告: 无法加载HTML解析器配置，使用默认配置: %v\n", err)
		config = &HTMLParserConfig{
			RemoveScripts: false,
			RemoveStyles:  false,
			IncludeImages: false,
			BaseURL:       "",
			MaxDepth:      0,
		}
	}
	log.Printf("HTML解析器配置: %+v\n", config)

	// 初始化HTML解析器配置
	htmlConfig := &html.Config{
		//	Selector: "#content",
	}

	// 初始化解析器
	p, err := html.NewParser(ctx, htmlConfig)
	if err != nil {
		return nil, fmt.Errorf("初始化HTML解析器失败: %w", err)
	}

	// 准备解析选项
	options := []parser.Option{}

	// 使用传入的URI参数
	if uri != "" {
		options = append(options, parser.WithURI(uri))
	}

	// 使用传入的额外元数据
	if extraMeta != nil {
		options = append(options, parser.WithExtraMeta(extraMeta))
	}

	// 使用传入的HTML内容进行解析
	docs, err := p.Parse(ctx, strings.NewReader(string(htmlContent)), options...)
	if err != nil {
		return nil, fmt.Errorf("解析HTML文档失败: %w", err)
	}

	return docs, nil
}

// loadHTMLParserConfig 从TOML文件加载HTML解析器配置
func loadHTMLParserConfig() (*HTMLParserConfig, error) {
	// 获取当前文件所在目录
	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		dir = "."
	}

	// 配置文件路径
	configPath := filepath.Join(dir, "parser_config.toml")

	// 检查配置文件是否存在
	if _, err := os.Stat(configPath); os.IsNotExist(err) {
		return nil, fmt.Errorf("配置文件不存在: %s", configPath)
	}

	// 读取配置文件
	data, err := os.ReadFile(configPath)
	if err != nil {
		return nil, fmt.Errorf("读取配置文件失败: %w", err)
	}

	// 解析TOML配置
	var config struct {
		HTMLParser HTMLParserConfig `toml:"html_parser"`
	}
	err = toml.Unmarshal(data, &config)
	if err != nil {
		return nil, fmt.Errorf("解析TOML配置失败: %w", err)
	}

	return &config.HTMLParser, nil
}

// PDFParserConfig PDF解析器配置结构
type PDFParserConfig struct {
	ToPages      bool   `toml:"to_pages"`      // 是否按页面分割
	ExtractText  bool   `toml:"extract_text"`  // 是否提取文本
	ExtractImage bool   `toml:"extract_image"` // 是否提取图片
	MaxPages     int    `toml:"max_pages"`     // 最大处理页数
	Password     string `toml:"password"`      // PDF密码（如果有）
}

// ParsePDF 解析PDF文档
// 参数:
//   - ctx: 上下文
//   - pdfContent: PDF内容字节数组
//   - uri: 可选的文档URI
//   - extraMeta: 可选的额外元数据
//
// 返回:
//   - []*schema.Document: 解析后的文档列表
//   - error: 错误信息
func ParsePDF(ctx context.Context, pdfContent []byte, uri string, extraMeta map[string]any) ([]*schema.Document, error) {
	// 参数验证
	if pdfContent == nil {
		return nil, fmt.Errorf("%w: PDF内容不能为空", ErrInvalidParameter)
	}

	// 加载配置
	config, err := loadPDFParserConfig()
	if err != nil {
		// 如果加载配置失败，使用默认配置并记录警告
		fmt.Printf("警告: 无法加载PDF解析器配置，使用默认配置: %v\n", err)
		config = &PDFParserConfig{
			ToPages:      false,
			ExtractText:  true,
			ExtractImage: false,
			MaxPages:     0, // 0表示无限制
		}
	}

	// 初始化解析器配置
	pdfConfig := &pdf.Config{
		ToPages: config.ToPages,
	}

	// 初始化解析器
	p, err := pdf.NewPDFParser(ctx, pdfConfig)
	if err != nil {
		return nil, fmt.Errorf("初始化PDF解析器失败: %w", err)
	}

	// 准备解析选项
	parseOptions := []parser.Option{}
	if uri != "" {
		parseOptions = append(parseOptions, parser.WithURI(uri))
	}
	if extraMeta != nil && len(extraMeta) > 0 {
		parseOptions = append(parseOptions, parser.WithExtraMeta(extraMeta))
	}

	// 解析文档（使用传入的pdfContent）
	docs, err := p.Parse(ctx, strings.NewReader(string(pdfContent)), parseOptions...)
	if err != nil {
		return nil, fmt.Errorf("解析PDF文档失败: %w", err)
	}

	return docs, nil
}

// loadPDFParserConfig 从TOML文件加载PDF解析器配置
func loadPDFParserConfig() (*PDFParserConfig, error) {
	// 获取当前文件所在目录
	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		dir = "."
	}

	// 配置文件路径（使用与HTML解析器相同的配置文件）
	configPath := filepath.Join(dir, "parser_config.toml")

	// 检查配置文件是否存在
	if _, err := os.Stat(configPath); os.IsNotExist(err) {
		return nil, fmt.Errorf("配置文件不存在: %s", configPath)
	}

	// 读取配置文件
	data, err := os.ReadFile(configPath)
	if err != nil {
		return nil, fmt.Errorf("读取配置文件失败: %w", err)
	}

	// 解析TOML配置
	var config struct {
		PDFParser PDFParserConfig `toml:"pdf_parser"`
	}
	err = toml.Unmarshal(data, &config)
	if err != nil {
		return nil, fmt.Errorf("解析TOML配置失败: %w", err)
	}

	return &config.PDFParser, nil
}

// ParseDocument 根据文件扩展名自动选择合适的解析器
// 参数:
//   - ctx: 上下文
//   - content: 文档内容或文件路径
//   - format: 文档格式 (html, pdf, text等)
//   - isPath: content是否为文件路径(true)或内容本身(false)
//
// 返回:
//   - []*schema.Document: 解析后的文档列表
//   - error: 错误信息
func ParseDocument(ctx context.Context, content string, format string, isPath bool) ([]*schema.Document, error) {
	// 参数验证
	if content == "" {
		return nil, fmt.Errorf("%w: 内容或文件路径不能为空", ErrInvalidParameter)
	}

	// 转换格式为小写以便比较
	format = strings.ToLower(format)

	// 根据格式选择解析方法
	switch format {
	case "html", "htm":
		if isPath {
			// 如果是路径，先读取文件内容
			htmlContent, err := os.ReadFile(content)
			if err != nil {
				return nil, fmt.Errorf("读取HTML文件失败: %w", err)
			}
			return ParseHTML(ctx, htmlContent, content, nil)
		}
		// 直接解析HTML内容
		return ParseHTML(ctx, []byte(content), "", nil)

	case "pdf":
		if isPath {
			// 如果是路径，先读取文件内容
			pdfContent, err := os.ReadFile(content)
			if err != nil {
				return nil, fmt.Errorf("读取PDF文件失败: %w", err)
			}
			return ParsePDF(ctx, pdfContent, content, nil)
		}
		// 直接解析PDF内容
		return ParsePDF(ctx, []byte(content), "", nil)

	case "text", "txt":
		// 文本解析功能暂未实现
		return nil, fmt.Errorf("%w: 文本解析功能暂未实现", ErrParseDocumentFailed)

	default:
		return nil, fmt.Errorf("%w: %s", ErrUnsupportedFormat, format)
	}
}

// 辅助函数：读取文件内容
func readFileContent(filePath string) (string, error) {
	content, err := readFile(filePath)
	if err != nil {
		return "", err
	}
	return string(content), nil
}

// 辅助函数：打开文件
func openFile(filePath string) (io.Reader, error) {
	file, err := os.Open(filePath)
	if err != nil {
		return nil, err
	}
	return file, nil
}

// 辅助函数：读取文件内容
func readFile(filePath string) ([]byte, error) {
	return os.ReadFile(filePath)
}
